package com.test.springboot.springBootUtils.redis;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * 使用 Redisson 实现分布式锁
 * @author My
 *
 */
public class RedissonLock {
	@Autowired
	private Redisson redisson; 
	public String deductStock() {
		final String lockKey = "lockKey";// 分布式锁的key
		//获取锁
		RLock redissonLock = redisson.getLock(lockKey);
		try {
			//加锁
			redissonLock.lock();//相当于:stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);
			
			/* 
			 * 
			 * 这里处理业务代码
			 * 
			 */
		
			return "Success";
		} catch (Exception e) {
			// 这里业务代码出现异常 开始异常的补偿
			return "fail";
		} finally {
			//释放锁
			redissonLock.unlink(); 
		}

		
		/**
		 * Redis key的设置时间问题:
		 * Redis 的key 的设置时间  到底应该设置多长，如果太短，业务代码没有执行完成，但是锁已经被Redis释放，如果太长 中间宕机 当前锁释放需要等待很长时间
		 * 解决方法：
		 * 	锁续命，在开始执行业务代码的时候 开启一个线程 监控当前锁的过期时间，如果快要过期 ，但是业务代码还未执行完毕，这时候重新设置当前key 的过期时间
		 *  解决方法有 :Redission 解决
		 */

		/**
		 * Redisson 加锁底层使用的是 Lua 脚本
		 */
		
		/**
		 * 
		 * Redis 哨兵的  模式 Redis锁的问题 锁的失效问题:
		 * 如果Redis架构为哨兵模式的主从架构，当在master 节点拿到锁，但是数据未同步到 slave   这时候 master 节点宕机 ，slave 节点升级为master  时，在新的
		 * master 中没有当前锁，第二个线程也能拿到锁，会造成超卖的局面
		 * 原因:Redis 不能支持数据的强一致性  
		 * 解决办法：
		 * 1.使用ZK (设置数据的key 之后，不会马上返回客户端，等到半数以上的节点数据同步成功之后才返回客户端，这样在master 节点宕机之后，重新选举的节点也会有当前的数据)
		 * 2.使用Redlock的实现原理: 向所有节点set 数据，当半数以上的成功之后才返回 (不推荐使用) 原因有:这样就不能是主从节点，只能是对等节点，当某些节点加锁失败 ，需要数据回滚
		 */
	}

}
